import * as d3 from "d3"
import moment, { months } from "moment"
import { computeMothMap, computeDayTicks, computeMonthTicks } from "../helper"
import { series } from "./data.mjs"
let _clipId = 0, _xAxisClipPath = "x-axis-clipPath", _yAxisClipPath = "y_axis_clip_path"

let _cache = {}

function createClipPath(svg, clipId, { x, y, width, height }) {
    let selection = svg.select(`#${clipId}`)
    if (selection.empty()) {
        let defs = svg.select("defs")
        selection = defs.append("clipPath")
            .attr("id", clipId)
            .append("rect")
            .attr("x", x)
            .attr("y", y)
            .attr("width", width)
            .attr("height", height);

    }

    return selection

}

function createLine(svg, ctx) {
    const { marginLeft, width, marginRight, x1, x2, y, className = "month-line", height, marginBottom } = ctx

    let clipId = _xAxisClipPath
    createClipPath(svg, clipId, { x: x1, y: -60, width: x2 - x1, height: height - marginBottom })

    let lineG = svg.append("g").attr('transform', `translate(0,${y})`)
        .attr("clip-path", `url(#${clipId})`)

    lineG.append("rect")
        .attr("x", x1)
        .attr("y", -60)
        .attr("width", x2 - x1)
        .attr("height", 60)
        .attr("fill", "red")

    lineG.append("line")
        .attr("class", className)
        .attr("stroke", "black")
        .attr('stroke-width', 2)
        .attr('x1', x1)
        .attr('x2', x2)

    return lineG

}


function appendTick({ line, x, text, step, scale }) {
    //    let clipPath = svg.append("clipPath")
    //     .append("rect")
    //     .attr("x", marginLeft)
    //     .attr("y", marginTop)
    //     .attr("width", width - marginLeft - marginRight)
    //     .attr("height", height - marginTop - marginBottom);

    let fontSize = 14
    let monthText = moment(text).format("YYYY-MM")
    let showMonth = fontSize * monthText.length * 0.9 <= step
    // showMonth = true

    let tick = line.append('g').attr("class", "tick x-row-tick").attr("opacity", 1).attr("transform", `translate(${x},0)`)
    tick.append("line").attr("y2", -46).attr("stroke", "currentColor")
    tick.append("line").attr("class", "split-line").attr("y2", 0).attr("stroke-width", 1).attr("stroke", "rgba(0,0,255,0.4)")
    tick.append("text").attr("x", step * 0.5).attr("y", -29)
        .attr("text-anchor", "middle")
        .attr("visibility", showMonth ? "visible" : "hidden")
        .attr('font-size', `${fontSize}px`)
        .text(() => {
            return monthText

        })

    let dayCount = moment(text).daysInMonth();
    let dayWidth = 20
    let planCount = Math.round(step / dayWidth)
    let stepDay = Math.ceil(dayCount / planCount)
    let startDay = moment(text).startOf("month")
    let endDay = moment(text).endOf("month")

    planCount = Math.ceil(dayCount / stepDay)

    let days = []
    Array(planCount).fill(0).map((t, index) => {
        if (index > 0) {
            let d = moment(startDay).add(index * stepDay, "days")
            if (d.isBefore(endDay)) {
                days.push(d)
            }

        }

    })

    days.forEach(d => {
        let dayX = scale(d)
        let tick = line.append('g').attr("class", "tick x-row-tick").attr("opacity", 1).attr("transform", `translate(${dayX},0)`)
        tick.append("line").attr("y2", -6).attr("stroke", "currentColor")
        tick.append("line").attr("class", "split-line").attr("y2", 0).attr("stroke-width", 0.3).attr("stroke", "rgba(0,0,0,0.3)")
        tick.append("text").attr("y", -9)
            .attr("text-anchor", "middle")
            .attr("visibility", "visible")
            .attr("font-size", "12px")
            .text(() => {
                return moment(d).format("DD")

            })
    })

    // let ddDescs_ = days.map(t => moment(t).format("YYYY-MM-DD"))
    // console.log("ddDescs_", ddDescs_, planCount, dayCount, stepDay, moment(text).format("YYYY-MM"), startDay.format("YYYY-MM-DD"), endDay.format("YYYY-MM-DD"))

}


function createSvg(ctx) {
    const { width, height, marginTop, marginRight, marginBottom, marginLeft } = ctx
    const svg = d3.create("svg")
        .attr("class", "svg-gantt")
        .attr("viewBox", [0, 0, width, height])
        .attr("width", width)
        .attr("height", height)
        .attr("style", "max-width: 100%; height: auto;");

    const defs = svg.append("defs")
    return svg
}

function createXAxis(svg, ctx) {
    const { width, height, marginTop, marginRight, marginBottom, marginLeft, startTime, endTime } = ctx

    let xConfig = {
        x1: marginLeft,
        x2: width - marginRight,
        y: marginTop,
    }
    ctx = { ...ctx, ...xConfig }

    const { x1, x2, y } = xConfig

    const xScale = d3.scaleTime()
        .domain([startTime, endTime])
        .range([x1, x2]);

    const xAxis = (g, x) => {
        g.call(d3.axisTop(x).ticks(width / 80).tickSizeOuter(0))
    }

    const gx = svg.append("g")
        .attr("transform", `translate(0,${y * 1.5})`)
        .attr("visibility", "hidden")
        .call(xAxis, xScale);


    const zoom = d3.zoom()
        .scaleExtent([5, 50])
        .extent([[x1, 0], [x2, 0]])
        .translateExtent([[x1, -0], [x2, 0]])
        .on("zoom", zoomed);


    function zoomed(event) {
        const xz = event.transform.rescaleX(xScale);
        // console.log("xz", xz.domain())
        gx.call(xAxis, xz);

        let domain = xz.domain()
        createMonth(domain, xz)

    }

    function createMonth(domain, scale) {
        let mm = computeMothMap(domain[0], domain[1])
        let ticks = computeMonthTicks(mm)
        let months = ticks.map(t => moment(t).startOf('month'))

        if (ctx.xRowLine) {
            ctx.xRowLine.remove()
        }
        ctx.xRowLine = createLine(svg, { ...ctx, className: "xRowLine" })

        months.forEach(m => {
            let nextMonth = moment(m).add(1, 'month').startOf('month')
            let step = scale(nextMonth) - scale(m)
            let x = scale(m)
            appendTick({ line: ctx.xRowLine, x, text: m, step, scale })

        })

        createRowSplitLines(svg, ctx.xRowLine, ctx)
    }

    // Initial zoom.
    svg.call(zoom)
        .transition()
        .duration(750)
        .call(zoom.scaleTo, 5, [xScale(moment(startTime)), 0]);


    return { xScale, xAxis, gx }
}

function createYAxis(svg, ctx) {
    const { width, height, marginTop, marginRight, marginBottom, marginLeft, startTime, endTime } = ctx
    const _series = series.slice()
    let maxLevel = _series.length, _currentK = 1
    let yDatas = updateDomains()

    const minH = 140;
    const y1 = marginTop, translateY = marginTop - y1, y2 = height - marginBottom
    //y轴
    const yRang = [y1, y2]
    const yScale = d3.scaleBand(yDatas, yRang).padding(0).align(0);

    // console.log("lastOffset", yScale("y0"), yScale("y19"), yScale.bandwidth())

    const yAxis = d3.axisLeft(yScale).tickSizeOuter(0)

    let box = {
        x: -marginLeft,
        y: marginTop,
        width: marginLeft + 10,
        height: height - marginTop - marginBottom
    }

    let clipId = _yAxisClipPath
    createClipPath(svg, clipId, { ...box })

    const gy = svg.append("g")
        .attr("clip-path", `url(#${clipId})`)
        .attr("class", "y-axis")
        .attr("transform", `translate(${marginLeft * 1},${translateY})`)
        .call(yAxis, yScale);


    const yZoomRect = gy.append("rect")
        .attr("x", box.x)
        .attr("y", box.y)
        .attr("width", box.width)
        .attr("height", box.height)
        .attr("fill", 'rgba(255,0,0,0.4)')
    // .attr("clip-path", `url(#${clipId})`)


    function updateDomains() {
        console.log("_currentK", _currentK)
        return _series[_currentK - 1].map(d => d.key)
    }

    function createZoom(selection) {
        let zoom = d3.zoom()
            .scaleExtent([1, maxLevel])
            .translateExtent([[0, y1], [0, y2]])
            .extent([[0, y1], [0, height - marginBottom]])
            .on("zoom", zoomed)

        function zoomed(event) {
            let nextK = event.transform.k
            console.log("zoom", event.transform.y, Math.abs(nextK - _currentK))

            let threshold = 0.9
            if (Math.abs(nextK - _currentK) < threshold) {
                yScale.range(yRang.map(d => event.transform.applyY(d)));
                gy.call(yAxis);

            } else {
                // let domains = yScale.domain().slice()
                if (nextK > _currentK) {
                    //放大，增加元素
                    console.log("放大", nextK, _currentK)
                    // let len = domains.length
                    // domains.push("y-" + len)
                } else {
                    //缩小，删除元素
                    console.log("减少", nextK, _currentK)
                    // domains.pop()
                }
                _currentK = Math.round(nextK)
                // let bandWidth = yScale.bandwidth()
                let domains = updateDomains()

                yScale.domain(domains)
                gy.call(yAxis);

            }
        }

        selection.call(zoom)

        // Initial zoom.

        // let vv = -1 * (yScale("y6") - yScale("y0"))
        // console.log("vv", vv, yScale.bandwidth())
        // selection.call(zoom)
        //     .transition()
        //     .duration(750)
        //     .call(zoom.translateTo, 0, 0, [0, vv]);


        // let vv = -1 * (yScale("y6") - yScale("y0"))
        // console.log("vv", vv, yScale.bandwidth())
        // selection.call(zoom)
        //     .transition()
        //     .duration(750)
        //     .call(zoom.translateTo, 0, 0, [0, vv]);


    }
    createZoom(yZoomRect)

}

function createRowSplitLines(svg, selection, ctx) {
    let allRowTicks = selection.selectAll(".split-line")
    // console.log("*allRowTicks", allRowTicks)
    let arr = []
    allRowTicks.each(function (d) {
        let line = d3.select(this).attr("y1", 1000)
    })
}


const _ctx = {
    width: 1400,
    height: 500,
    marginTop: 60,
    marginRight: 5,
    marginBottom: 10,
    marginLeft: 30
}

function _chart() {
    let ctx = {
        ..._ctx,
        startTime: moment("2020-01-09"),
        endTime: moment("2024-11-09"),

    }
    const { width, height, marginTop, marginRight, marginBottom, marginLeft, startTime, endTime } = ctx

    let svg = createSvg(ctx)
    createXAxis(svg, ctx)
    createYAxis(svg, ctx)

    return svg.node();
}





document.body.appendChild(_chart())